package top.codef.formatterfactories;

import static java.util.stream.Collectors.toSet;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.money.MonetaryAmount;

import org.javamoney.moneta.FastMoney;
import org.javamoney.moneta.RoundedMoney;
import org.springframework.context.support.EmbeddedValueResolutionSupport;
import org.springframework.format.AnnotationFormatterFactory;
import org.springframework.format.Parser;
import org.springframework.format.Printer;

import top.codef.anno.Money;
import top.codef.formatters.FastMoneyFormatter;
import top.codef.formatters.MonetaMoneyFormatter;
import top.codef.formatters.MoneyFormatter;
import top.codef.formatters.RoundedMoneyFormmatter;
import top.codef.money.interfaces.MercuryMonetaryAmountFormat;
import top.codef.properties.MercuryProperties;

public class MoneyFormatterFactory extends EmbeddedValueResolutionSupport
		implements AnnotationFormatterFactory<Money> {

	private final Set<Class<?>> fieldTypes = Arrays.stream(new Class<?>[] { FastMoney.class, MonetaryAmount.class,
			org.javamoney.moneta.Money.class, RoundedMoney.class }).collect(toSet());

	private final Map<Class<?>, MoneyFormatter<?>> formatMap = new HashMap<>();

	private MoneyFormatter<?> defaultMoneyFormatter;

	public MoneyFormatterFactory(MercuryProperties mercuryProperties,
			MercuryMonetaryAmountFormat mercuryMonetaryAmountFormat) {
		FastMoneyFormatter fastMoneyFormatter = new FastMoneyFormatter(mercuryProperties, FastMoney.class,
				mercuryMonetaryAmountFormat);
		formatMap.put(FastMoney.class, fastMoneyFormatter);
		formatMap.put(MonetaryAmount.class, fastMoneyFormatter);
		this.defaultMoneyFormatter = fastMoneyFormatter;
		MonetaMoneyFormatter monetaMoneyFormatter = new MonetaMoneyFormatter(mercuryProperties,
				org.javamoney.moneta.Money.class, mercuryMonetaryAmountFormat);
		formatMap.put(org.javamoney.moneta.Money.class, monetaMoneyFormatter);
		RoundedMoneyFormmatter roundedMoneyFormmatter = new RoundedMoneyFormmatter(mercuryProperties,
				RoundedMoney.class, mercuryMonetaryAmountFormat);
		formatMap.put(RoundedMoney.class, roundedMoneyFormmatter);
	}

	@Override
	public Set<Class<?>> getFieldTypes() {
		return fieldTypes;
	}

	public void add(Class<? extends MonetaryAmount> moneyClass, MoneyFormatter<? extends MonetaryAmount> formatter) {
		fieldTypes.add(moneyClass);
		formatMap.put(moneyClass, formatter);
	}

	@Override
	public Printer<?> getPrinter(Money annotation, Class<?> fieldType) {
		return formatMap.getOrDefault(fieldType, defaultMoneyFormatter);
	}

	@Override
	public Parser<?> getParser(Money annotation, Class<?> fieldType) {
		return formatMap.getOrDefault(fieldType, defaultMoneyFormatter);
	}
}
